﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
using System.Diagnostics;
using System.Windows.Threading;

using System.Windows.Controls.Primitives;

using System.Windows.Interop;
using System.Runtime.InteropServices;
using Microsoft.Practices.Composite.Presentation.Commands; 

using avlib_wrapper;

namespace dmm
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    /// 
  
    
    public partial class Window1 : Window,RecorderObserver
    {
        #region private members
        private DBAcess dba = new DBAcess();
        private ArrayList video_list = new ArrayList();
       // private Options options;

        private PipeRecordController record_control = null;


       // @pragma 

        private DlgRecordControl wndRecordCtrl = null;
        //private AVRecorderWrapper recorder = null;
        private Recorder recorder = null;
        private Encoder encoder = null;

        private Video current_video;
        //capture url
        private string strUrl="";
        #endregion


        #region properties
        public VideoPlayer thePlayer
        {
            get { return player; }
        }
        #endregion


        #region commands
        public DelegateCommand<object> CommandAddVideo { get; set; }
        public DelegateCommand<object> CommandRecordVideo { get; set; }
        public DelegateCommand<object> CommandDeleteVideo { get; set; }
        public DelegateCommand<object> CommandPlayVideo { get; set; }
        public DelegateCommand<object> CommandConvertVideo { get; set; }
        public DelegateCommand<object> CommandSearchVideo { get; set; }


        public DelegateCommand<object> CommandStartTask { get; set; }
        public DelegateCommand<object> CommandStopTask { get; set; }
        public DelegateCommand<object> CommandDeleteTask { get; set; }

        public DelegateCommand<object> CommandAppAbout { get; set; }
        public DelegateCommand<object> CommandAppExit { get; set; }

       
        /*public static RoutedUICommand CmdAddVideo = new RoutedUICommand("Add Videos", "AddVideo", typeof(Window1));
        public static RoutedUICommand CmdRecordVideo = new RoutedUICommand("Record a Video", "RecordVideo", typeof(Window1));
        public static RoutedUICommand CmdDeleteVideo = new RoutedUICommand("Delete selected Video", "CmdDeleteVideo", typeof(Window1));
        public static RoutedUICommand CmdPlayVideo = new RoutedUICommand("Play the Video", "CmdPlayVideo", typeof(Window1));
        public static RoutedUICommand CmdConvertVideo = new RoutedUICommand("Convert Selected Videos", "CmdConvertVideo", typeof(Window1));


        public static RoutedUICommand CmdStartTask = new RoutedUICommand("Start Task", "CmdStartTask", typeof(Window1));
        public static RoutedUICommand CmdStopTask = new RoutedUICommand("Start Task", "CmdStopTask", typeof(Window1));
        public static RoutedUICommand CmdDeleteTask = new RoutedUICommand("Delete Task", "CmdDeleteTask", typeof(Window1));


        public static RoutedUICommand CmdAppAbout = new RoutedUICommand("About...", "CmdAppAbout", typeof(Window1));
        public static RoutedUICommand CmdAppExit = new RoutedUICommand("Exit", "CmdAppExit", typeof(Window1));*/

        #endregion

        //a conversion finished successfuly
        public void onTaskFinished(Task t)
        {
          
            dba.add_video(VideoSourceType.VideoFromConversion,t.video.Name, t.target_file, t.video.Thumbnail, t.target_width,t.target_height,t.TargetDuration);
            refresh_video_list();
            return;
            
        }

        public String FilterString
        {
            get;
            set;
        }
        public Window1()
        {
            FilterString = String.Empty;

            CommandAddVideo = new DelegateCommand<object>(DoAddVideo, delegate(object obj) { return true; });
            CommandRecordVideo = new DelegateCommand<object>(DoRecordVideo, CanRecordVideo);
            CommandDeleteVideo = new DelegateCommand<object>(DoDeleteVideo, CanDeleteVideo);
            CommandPlayVideo = new DelegateCommand<object>(DoPlayVideo, CanPlayVideo);
            CommandConvertVideo = new DelegateCommand<object>(DoConvertVideo, CanConvertVideo);
            CommandSearchVideo = new DelegateCommand<object>(DoSearchVideo, CanSearchVideo);

            CommandStartTask = new DelegateCommand<object>(DoStartTask, CanStartTask);
            CommandStopTask = new DelegateCommand<object>(DoStopTask, CanStopTask);
            CommandDeleteTask = new DelegateCommand<object>(DoDeleteTask, CanDeleteTask);

            CommandAppAbout = new DelegateCommand<object>(DoAppAbout, delegate(object obj) { return true; });
            CommandAppExit = new DelegateCommand<object>(DoAppExit, delegate(object obj) { return true; });

            InitializeComponent();
        }


        private void onRecordOptionDlgClose(object sender, EventArgs e)
        {
            
            DlgRecordOption dlg = sender as DlgRecordOption;
            if (dlg.Selection)
            {
                start_record();
            }
        }

        private void DoRecordVideo(object sender)
        {
            //this.WindowState = WindowState.Minimized;

            DlgRecordOption dlg = new DlgRecordOption(recorder);
            dlg.Owner = this;
            dlg.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;

            dlg.Closed += onRecordOptionDlgClose;
            dlg.Show();
        }

        private void DoAppAbout(object sender)
        {
        }

        private void DoAppExit(object sender)
        {
            player.stop();
            this.Close();
            Application.Current.Shutdown();
        }

        private void refresh_video_list()
        {
            foreach (Video v in video_list)
            {
                if (v.IsDirty)
                {
                    dba.update_video(v);
                }
            }


            video_list_ctrl.Items.Clear();
            video_list.Clear();

            dba.db_connect();
            video_list_ctrl.DisplayMemberPath = "name";

            dba.load_videos( video_list,FilterString);

            //how to set video_list as data model of video_list_ctrl
            foreach (Video v in video_list)
            {
                v.VideoSetting = VideoEditSettings.get_setting(v.ID);
                video_list_ctrl.Items.Add(v);
            }

            

          
        }

        private void refresh_task_list()
        {
            task_list_ctrl.Items.Clear();
          
            //how to set video_list as data model of video_list_ctrl
            foreach (Task t in encoder.tasks)
            {
               task_list_ctrl.Items.Add(t);
            }

        }

        private void DoAddVideo(object sender)
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.FileName = "";
            dlg.DefaultExt = ".avi";
            dlg.Multiselect = true;
            dlg.Filter = @"AVI Video|*.avi|MP4 Video|*.mp4|Flash Video|*.flv|Matroska Video|*.mkv|All files|*.*";

            Nullable<bool> result = dlg.ShowDialog();

            // Process open file dialog box results 
            if (result == true)
            {
                // Open document 
                for (int i = 0; i < dlg.FileNames.Count(); i++)
                {
                    string filename = dlg.FileNames[i];
                    //Debug.Write("select " + filename + "\n");
                    dba.add_video(VideoSourceType.VideoFromLocal, "", filename, "", 320, 240, 100);
                }

                refresh_video_list();
            }

        }

        private void DoDeleteVideo(object sender)
        {
            MessageBoxResult result = MessageBox.Show("Are you sure to delete these videos", "Confirm",System.Windows.MessageBoxButton.YesNo);
            if (result == MessageBoxResult.Yes)
            {
                foreach (Video v in video_list_ctrl.SelectedItems)
                {
                    VideoEditSettings.remove_setting(v.ID);
                    dba.delete_video(v.ID);
                }
                refresh_video_list();
            }
        }

        bool CanRecordVideo(object sender)
        {
            return (player!=null && !player.IsRecording);
        }
        bool CanPlayVideo(object sender)
        {
            return ((video_list_ctrl != null) && video_list_ctrl.SelectedItems.Count > 0);
        }

        bool CanConvertVideo(object sender)
        {
            return ((video_list_ctrl != null) && video_list_ctrl.SelectedItems.Count > 0);
        }

        bool CanDeleteVideo(object sender)
        {
            return ((video_list_ctrl!= null) && video_list_ctrl.SelectedItems.Count > 0);
        }

        bool CanStartTask(object sender)
        {
            //return (task_list_ctrl.SelectedItems.Count > 0);
            Task t = task_list_ctrl.SelectedItem as Task;
            if (t != null)
                return t.CanStart;
            else
                return false;
        }

        bool CanStopTask(object sender)
        {
            Task t = task_list_ctrl.SelectedItem as Task;
            if (t != null)
                return t.CanStop;
            else
                return false;
        }

        bool CanDeleteTask(object sender)
        {
            return (task_list_ctrl.SelectedItems.Count > 0);
        }

        bool CanSearchVideo(object filter)
        {
            return true;
        }
        private void DoSearchVideo(object filter)
        {
            refresh_video_list();
        }

        private void DoConvertVideo(object sender)
        {
            Profile p = profile_manager.SelectedProfile;
            if (p == null)
            {
                MessageBox.Show("please select a output video profile first");
                profile_manager.Focus();
                return;
            }

            foreach (Video v in video_list_ctrl.SelectedItems)
            {
                Task t = new Task(v, p,null);

                encoder.add_task(t);
                
            }
            refresh_task_list();
        }

        private void DoPlayVideo(object sender)
        {
            player.theVideo = current_video;
            player.play();
            Tab.SelectedIndex = 0;
        }

        private void onConvertVideo(object sender, RoutedEventArgs e)
        {
            //current_video.

            Profile p = profile_manager.SelectedProfile;
            if (p == null)
            {
                MessageBox.Show("please select a output video profile first");
                profile_manager.Focus();
                return;
            }
            if (p != null && player.theVideo != null)
            {
                Task t = new Task(player.theVideo,p, null);
                
                encoder.add_task(t);
                refresh_task_list();
            }
            e.Handled = true;
            
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
         {
             
             recorder.stop();
             recorder.unregister_observer(this);
             if (record_control != null) record_control.close();
             
             player.close();
             encoder.stop_all();

             foreach (Video v in video_list)
             {
                 if (v.IsDirty)
                 {
                     dba.update_video(v);
                 }
             }
             dba.db_close();
             base.OnClosing(e);
           
         }


        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            Application.Current.Shutdown();
        }

        
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.DataContext = this;
            /*CommandBindings.Add(new CommandBinding(CmdAddVideo,onAddVideo));
            CommandBindings.Add(new CommandBinding(CmdRecordVideo,onRecordVideo));
            CommandBindings.Add(new CommandBinding(CmdDeleteVideo, onDeleteSelected,CanDeleteVideo));
            CommandBindings.Add(new CommandBinding(CmdConvertVideo, onConvertSelected));
            CommandBindings.Add(new CommandBinding(CmdPlayVideo, onPlaySelected));

            CommandBindings.Add(new CommandBinding(CmdStartTask,onTaskStart));
            CommandBindings.Add(new CommandBinding(CmdStopTask,onTaskStop));
            CommandBindings.Add(new CommandBinding(CmdDeleteTask,onTaskDelete));

            CommandBindings.Add(new CommandBinding(CmdAppAbout,onAppAbout));
            CommandBindings.Add(new CommandBinding(CmdAppExit,onAppExit));*/
            recorder = new Recorder();
            recorder.Win = this;
            
            recorder.register_observer(this);
            record_control = new PipeRecordController(recorder);
            record_control.start();

            Options.Instance.OutputPath = @"c:\dsfds";

            encoder = new Encoder(this.onTaskFinished);
            refresh_video_list();

            
            

            //listen to WM_COPYDATA,deprecayed,use named pipe instead
            //HwndSource hs = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
            //hs.AddHook(new HwndSourceHook(onCopyData));

            //player.VideoCommited = OnCommitVideo;
            player.btnConvert.Click += onConvertVideo;
            player.Recorder = recorder;

            player.MainWindow = this;
            
        }


        

        private void DoStartTask(object sender)
        {
            foreach (Task t in task_list_ctrl.SelectedItems)
            {
                //Task t = (Task)task_list_ctrl.ItemContainerGenerator.ItemFromContainer(item);
                encoder.start_task(t);
            }
        }
        private void DoStopTask(object sender)
        {
            foreach (Task t in task_list_ctrl.SelectedItems)
            {
                
                encoder.stop_task(t);
            }
        }
        private void DoDeleteTask(object sender)
        {
            foreach (Task t in task_list_ctrl.SelectedItems)
            {
                encoder.delete_task(t);
            }
            refresh_task_list();
        }

        public void onRecordStart()
        {
            //player.Status = VideoPlayer.PlayerStatus.RECORDING;
        }
        public void onRecordProgress(int frame, int samplecount)
        {
         //  string ext = "Frame:"+frame+",samplecount:"+samplecount;
          // this.Dispatcher.Invoke(new Action(() => {
           //    record_control.report(String.Format("SSTAT {0}", frame));
            //   player.set_play_progress(recorder.Duration);
          // }));
        }

        public void onRecordError(int err, string errtext)
        {
           // status_txt1.Text = "record error:" + errtext;
        }

        public void onRecordEnd()
        {
                current_video = recorder.RecordedVideo;
                dba.add_video(current_video);
                refresh_video_list();
                current_video = (Video)video_list[video_list.Count - 1];
                video_list_ctrl.ScrollIntoView(current_video);
        }

        public void stop_record()
        {
            recorder.stop();
        }

        private void start_record(){ 
            recorder.start();
           
            if (recorder.Setting.IsDesktopRecording)
            {
                //show record progress
               /* this.WindowState = WindowState.Minimized;

                wndRecordCtrl = new DlgRecordControl(recorder);
                wndRecordCtrl.Owner = this;
                wndRecordCtrl.ShowInTaskbar = false;
                wndRecordCtrl.Topmost = true;
                double sw = System.Windows.SystemParameters.PrimaryScreenWidth;
                double sh = System.Windows.SystemParameters.PrimaryScreenHeight;
                wndRecordCtrl.Left = sw - wndRecordCtrl.Width;
                wndRecordCtrl.Top = sh - 50 - wndRecordCtrl.Height;
                bool ret = (bool)wndRecordCtrl.ShowDialog();
                if (ret)
                {
                    //wndRecordCtrl.Show();
                    //restore window
                    WindowState = WindowState.Normal;                
                }*/
            }
        }

       
        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            player.adjust_layout();
        }

        private void Window_LocationChanged(object sender, EventArgs e)
        {
            player.adjust_layout();
        }

        private void video_list_ctrl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            //the best way to process item?
            DependencyObject dep = (DependencyObject)e.OriginalSource;

            while ((dep != null) && !(dep is ListViewItem))
            {
                dep = VisualTreeHelper.GetParent(dep);
            }

            if (dep == null) return;

            Tab.SelectedIndex = 0;
            //Video video = ((FrameworkElement)dep).DataContext as Video;
            Video video = (Video)video_list_ctrl.ItemContainerGenerator.ItemFromContainer(dep);

            current_video = video;
            player.theVideo= current_video;

            player.play();

            Debug.Write("double clicked " + video.Name );
        }

       
        public void set_caption(string txt){
           // status_txt1.Text = txt;
        }

       
        private void item_MouseEnter(object sender, MouseEventArgs e)
        {
            video_info.DataContext = (sender as FrameworkElement).DataContext;
            video_info.PlacementTarget = (sender as UIElement);
            video_info.IsOpen = true;
        }

        private void item_MouseLeave(object sender, MouseEventArgs e)
        {
            video_info.IsOpen = false;
        }



        [StructLayout(LayoutKind.Sequential)]
        public struct COPYDATASTRUCT
        {
            public UInt32 dwData;
            public UInt32 cbData;
            public IntPtr lpData;
        }
        public class Win32Consts
        {
            public const int WM_COPYDATA = 0x004A;
        }

       /* unsafe protected override void WndProc(ref Message message)
        {
            if (message.Msg == Win32Consts.WM_COPYDATA)
            {
                COPYDATASTRUCT cds =
                (COPYDATASTRUCT)message.GetLParam(typeof(COPYDATASTRUCT));

                string url = new string((char*)(cds.lpData), 0,cds.cbData / 2);
            }

            base.WndProc(ref message);
        }
        */

        [StructLayout(LayoutKind.Sequential)]
        struct RECT
        {
            public int left, top, right, bottom;
        }
        
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            public static implicit operator System.Drawing.Point(POINT p)
            {
                return new System.Drawing.Point(p.X, p.Y);
            }

            public static implicit operator POINT(System.Drawing.Point p)
            {
                return new POINT(p.X, p.Y);
            }
        }


        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetCursorPos(out POINT lpPoint);
        [DllImport("User32.dll")]
        static extern IntPtr WindowFromPoint(int x,int y);
        [DllImport("User32.dll")]
        static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
        [DllImport("User32.dll")]
        static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint);


        public void capture_current_window(int left,int top,int width,int height)
        {
            try
            {
                RECT rc = new RECT();

                rc.left = left;
                rc.top = top;
                rc.right = left + width;
                rc.bottom = top + height;

                POINT pt = new POINT();
                bool res = GetCursorPos(out pt);
                if (!res)
                {
                    Debug.Write("GetCursorPos(ref pt) error\n");
                }
                else
                {
                    Debug.Write("PoisiotnX:" + (int)pt.X + ",PositionY:" + (int)pt.Y + "\n");
                }
                IntPtr hwnd = WindowFromPoint((int)pt.X, (int)pt.Y);
                //GetClientRect(hwnd, out rc);
                pt.X = 0; pt.Y = 0;
                ClientToScreen(hwnd, ref pt);

                rc.left = (int)pt.X + left;
                rc.top = (int)pt.Y + top;
                rc.right = rc.left + width;
                rc.bottom = rc.top + height;




               
                recorder.Setting.VideoDevice = 0;
                recorder.Setting.AudioDevice = 0;
                recorder.Setting.FPS = 25;
                recorder.Setting.Left = rc.left;
                recorder.Setting.Top = rc.top;
                recorder.Setting.Width = width;
                recorder.Setting.Height = height;

                /*string avi_path = @"g:\tv\record\";
                string thumb_path = @"g:\tv\record\thumbnail\";
                setting.VideoFile = avi_path+ "canvas_"  + dba.get_id()+ ".avi";
                setting.ThumbnailFile = thumb_path + "canvas_" + dba.get_id() + ".avi.bmp";*/

                start_record();

            }
            catch (Exception e)
            {
                Debug.Write(e);
            }
        }

        private IntPtr onCopyData(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == Win32Consts.WM_COPYDATA)
            {
                COPYDATASTRUCT copydata = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));

                byte[] bytes = new byte[copydata.cbData];
                Marshal.Copy(copydata.lpData,bytes,0,(int)copydata.cbData);

                string cmd = System.Text.ASCIIEncoding.ASCII.GetString(bytes,0,4);

                if (cmd.Equals(@"STAT"))
                {
                    int left = BitConverter.ToInt32(bytes, 4);
                    int top = BitConverter.ToInt32(bytes, 8);
                    int width = BitConverter.ToInt32(bytes, 12);
                    int height = BitConverter.ToInt32(bytes, 16);
                   strUrl = System.Text.UTF8Encoding.ASCII.GetString(bytes, 20, (int)(copydata.cbData - 20));

                    Debug.Write(String.Format("received WM_COPYDATA,cmd:{0},{1},{2},{3},{4},{5}",cmd,left,top,width,height,strUrl));
                    capture_current_window(left, top, width, height);
                    
                }else if(cmd.Equals(@"STOP")){
                    recorder.stop();
                    wndRecordCtrl.Close();

                }
                

                handled = true;
            }

            return IntPtr.Zero;
        }

        private void video_list_ctrl_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Video v = (Video)video_list_ctrl.SelectedItem;
            current_video = v;
            if(player.theVideo == null)
                player.theVideo = v;
            CommandDeleteVideo.RaiseCanExecuteChanged();
            CommandPlayVideo.RaiseCanExecuteChanged();
            CommandConvertVideo.RaiseCanExecuteChanged();
        }



        private void task_list_ctrl_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
          
            CommandStartTask.RaiseCanExecuteChanged();
            CommandStopTask.RaiseCanExecuteChanged();
            CommandDeleteTask.RaiseCanExecuteChanged();
        }

        private void ToolBar_Loaded(object sender, RoutedEventArgs e)
        {
            ToolBar toolBar = sender as ToolBar;
            var overflowGrid = toolBar.Template.FindName("OverflowGrid", toolBar) as FrameworkElement;
            if (overflowGrid != null)
            {
                overflowGrid.Visibility = Visibility.Collapsed;
            }
        }

        private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.Source is TabControl)
            {
                if (playerTab.IsSelected)
                {
                    player.ShowPlayerWindow = true;
                }
                else
                {
                    player.ShowPlayerWindow = false;
                }
                e.Handled = true;
            }

        }

        private void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {

                FilterString = (sender as TextBox).Text;
                DoSearchVideo(null);
            }
        }

    }
}
